嗨大家,我是 Debuguy。
昨天聊完技術選型,今天要來談一個更有趣的問題:如何讓 LLM 知道「自己」是誰?
這聽起來像哲學問題,但其實是決定你的 ChatBot 是「工具」還是「夥伴」的關鍵分水嶺。
一開始,我的 System Prompt 超級簡單:
You are a helpful AI assistant. Answer the user's questions.
結果呢?我得到了一個非常稱職的智能客服:
👤 Debuguy:幫我查一下明天的會議
🤖 Bot:我無法訪問您的日曆系統。請您直接查看 Outlook 或 Google Calendar。
👤 Debuguy:這個 API 怎麼用?
🤖 Bot:根據文檔,您需要先進行身份驗證...
技術上完全正確,但感覺就是... 很工具。
我漸漸意識到,這不是功能問題,而是身份認知問題。
當 LLM 不知道「自己在哪裡」、「自己是誰」時,它就會默認自己是一個通用的 AI 助手。在 Slack 這個協作環境中,這種身份錯位會造成非常奇怪的對話體驗。
想像一下:如果有個新同事加入你們團隊,他每次回答問題都說「我是一個人類,我無法直接訪問您的系統」,你會不會覺得很奇怪?
在 LLM 的世界裡,身份認知就是讓它理解:
這不是讓 LLM 產生真正的「自我意識」,而是給它一個穩定的行為框架。
當我把 System Prompt 改成這樣時:
You are a helpful AI assistant operating as a Slack bot.
Your Slack ID is U09BASU9P6K.
The user who mentioned you is the one you must address in your reply.
When you finish your response, tag the user who originally mentioned you using their User ID, the format is <@USER_ID>.
突然間,對話的感覺就不一樣了:
👤 Debuguy:
@bot
幫我查一下明天的會議🤖 Bot:
@Debuguy
我目前還沒有連接到日曆系統的權限,但如果你需要的話,我可以請管理員幫忙設定!
👤 Debuguy:這個 API 怎麼用?
🤖 Bot:
@Debuguy
讓我看看我們文檔裡有什麼...
注意差異了嗎?同樣是無法直接完成任務,但第二個版本:
You are a helpful AI assistant operating as a Slack bot.
Your Slack ID is U09BASU9P6K.
這兩行看似簡單,但包含了三個關鍵資訊:
The user who mentioned you is the one you must address in your reply.
When you finish your response, tag the user who originally mentioned you using their User ID, the format is <@USER_ID>.
這是一個看似技術性的要求,但其實解決了一個很重要的社交問題。
在多人的 Slack 頻道中,如果 Bot 回復時沒有 mention 原始提問者,就會造成:
這個設計讓 Bot 學會了 Slack 的「社交禮儀」。
You will receive a message from a user in a Slack channel. format is <USER_ID>@<TIMESTAMP>: <MESSAGE>.
這個設計是為了解決一個實際問題:如何讓 LLM 從 Slack 的原始數據中提取出真正重要的資訊?
Slack 的原始事件長這樣:
{
"type": "app_mention",
"user": "U1234567890",
"text": "<@U09BASU9P6K> 今天天氣如何?",
"ts": "1699123456.123456",
"channel": "C1234567890",
"event_ts": "1699123456.123456",
"thread_ts": "1699123456.123456"
// ... 還有一堆其他資訊
}
如果直接把這個 JSON 丟給 LLM,它需要:
這太復雜了!所以我選擇在進入 LLM 之前就處理成:
U1234567890@1699123456.123456: 今天天氣如何?
這個格式:
讓我們看看這個設計在 GenKit 中是怎麼實現的:
const chatFlow = ai.defineFlow(
{
name: 'chatFlow',
inputSchema: z.object({
text: z.string(),
user: z.string(),
ts: z.string(),
}),
},
async ({ user, ts, text }) => (await ai.generate({
model: googleAI.model('gemini-2.5-flash-lite'),
system: `
You are a helpful AI assistant operating as a Slack bot.
Your Slack ID is U09BASU9P6K.
The user who mentioned you is the one you must address in your reply.
You will receive a message from a user in a Slack channel. format is <USER_ID>@<TIMESTAMP>: <MESSAGE>.
**Your Response Style:**
* Be helpful, friendly, and conversational.
* When you finish your response, tag the user who originally mentioned you using their User ID, the format is <@USER_ID>.
* Always maintain a natural, human-like tone while being clear that you're an AI assistant.
Remember: You are not just executing commands; you are participating in conversations as a helpful team member.
`,
prompt: `${user}@${ts}: ${text}`,
})).text
);
完整的原始碼
歡迎有興趣的人下載玩玩,體驗一下囉~
1. 結構化輸入
inputSchema: z.object({
text: z.string(),
user: z.string(),
ts: z.string(),
})
使用 Zod schema 確保輸入資料的正確性,同時也讓程式碼更容易測試和除錯。
2. 格式化 Prompt
prompt: `${user}@${ts}: ${text}`,
把複雜的 Slack 事件轉換成 LLM 容易理解的格式。
3. 明確的互動期待
Remember: You are not just executing commands; you are participating in conversations as a helpful team member.
這一句話改變了整個互動的感覺。從「執行指令」到「參與對話」,這是工具和夥伴的根本差異。
感受到差異了嗎?第二個版本:
Your Slack ID is U09BASU9P6K.
這個看似技術性的細節,其實有深層的意義:
1. 身份的具體化
2. self-referenc 的能力
3. 未來擴展的準備
看似簡單的 System Prompt 設計,其實解決了很多根本問題:
這就是我說的「從 0 到 1」的關鍵轉折點。不是技術上的突破,而是產品思維上的轉變:
從「讓 LLM 回答問題」到「讓 LLM 參與對話」
明天我們將回到技術層面,來看看 GenKit 這套開發框架是怎麼提供我們管理 prompt 的吧!
AI 的發展變化很快,目前這個想法以及專案也還在實驗中。但也許透過這個過程大家可以有一些經驗和想法互相交流,歡迎大家追蹤這個系列。
也歡迎追蹤我的 Threads @debuguy.dev